pub mod client;
pub mod cmd;
pub mod queue;

use base::{
    base::{Base, VBase, VMap},
    err, err_value, ok, throw_err, CRece, CSend, ECode, MapSv, RNull, Resp, VecV,
};
use bytes::Bytes;
use moka::future::Cache;
use serde_json::{json, Value};
use std::collections::HashSet;
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::Mutex;
use tracing::{instrument, warn};
use warp::{
    reject::Rejection,
    reply::{Json, WithStatus},
};

pub use client::{init_dir, Collect, Fbf, KeyNode, Rdb};
pub use queue::queue_chunk;

pub type SvCache = Cache<String, Value>;
pub type Lock = Arc<Mutex<()>>;
pub type Sub<'a> = Option<&'a str>;
pub type Client = Rdb;
pub type SStr = HashSet<String>;
pub type VecSv = Vec<(String, Value)>;
pub type VecS = Vec<String>;

#[instrument(skip_all, name = "s")]
pub async fn do_cmd(
    data: Bytes,
    model: String,
    cmd: String,
    name: Option<String>,
    client: &Client,
    cache: SvCache,
    lock: Lock,
    tx: CSend,
) -> Result<WithStatus<Json>, Rejection> {
    let val = match base::do_byte(data) {
        Ok(v) => v,
        Err(e) => {
            warn!("error val: {:?} - {:?}", &e, cmd);

            return Ok(base::ret_err(&e, None));
        }
    };

    let start = Instant::now();

    match cmd::doit(
        &val,
        &model,
        &cmd,
        name.as_ref().map(|x| x.as_str()),
        client,
        cache,
        lock,
        tx,
    )
    .await
    {
        Ok(v) => {
            let duration = start.elapsed();
            warn!(
                "dt: {:?} - end model: {:?} - name: {:?} - cmd: {:?} - para: {:?}",
                duration, model, name, cmd, val
            );

            Ok(base::ret_ok(&v))
        }
        Err(e) => {
            let duration = start.elapsed();
            warn!(
                "dt: {:?} - error: {:?} - model: {:?} - name: {:?} - cmd: {:?} - para: {:?}",
                duration, &e, model, name, cmd, val
            );

            Ok(base::ret_err(&e, None))
        }
    }
}
